package com.rn.ddd.infrastructure.base;

import com.rn.ddd.infrastructure.engine.OrderEvent;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 领域事件发布者
 *
 * @author 然诺
 * @date 2022/3/26
 */
public class DomainEventPublisher {

    private static final ThreadLocal<List> subscribers = new ThreadLocal<>();
    private static final ThreadLocal<Boolean> publishing = ThreadLocal.withInitial(() -> false);

    public static DomainEventPublisher instance() {
        return new DomainEventPublisher();
    }

    public <T> void publish(final T domainEvent) {
        if (publishing.get()) {
            return;
        }
        try {
            publishing.set(true);
            List<DomainEventSubscriber<T>> subscriberList = subscribers.get();
            if (CollectionUtils.isEmpty(subscriberList)) {
                return;
            }
            Class<?> eventType = domainEvent.getClass();
            for (DomainEventSubscriber<T> subscriber : subscriberList) {
                Class<?> subscribedTo = subscriber.subscribedToEventType();
                if (subscribedTo == eventType || subscribedTo == OrderEvent.class) {
                    subscriber.handleEvent(domainEvent);
                }
            }
        } finally {
            publishing.set(false);
        }
    }

    public <T> void subscribe(DomainEventSubscriber<T> subscriber) {
        if (publishing.get()) {
            return;
        }
        List<DomainEventSubscriber<T>> registeredSubscribers = subscribers.get();
        if (CollectionUtils.isEmpty(registeredSubscribers)) {
            registeredSubscribers = new ArrayList<>();
            subscribers.set(registeredSubscribers);
        }
        registeredSubscribers.add(subscriber);
    }

    public DomainEventPublisher reset(){
        if (!publishing.get()) {
            subscribers.set(null);
        }
        return this;
    }

}
